package cn.itcast.poi.controller;

import cn.itcast.poi.entity.User;
import cn.itcast.poi.service.UserService;
import cn.itcast.poi.utils.export.ExcelExportWithoutTemplateUtil;
import cn.itcast.poi.utils.export.ExcelWithTemplateExportUtil;
import cn.itcast.poi.utils.fastdfs.FastDFSClient;
import cn.itcast.poi.utils.fastdfs.FastDFSFile;
import cn.itcast.poi.utils.importData.ExcelImportUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.poi.util.IOUtils;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.nio.channels.FileChannel;
import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/user")
@Slf4j
public class UserController {

    @Autowired
    private UserService userService;

    /**
     * 文件上传,所有数据都合法的话再向数据库中批量添加数据,若有一条不合法,则将不能导入的原因逐条写到原excel中并上传至fastdfs,然后将下载地址返回给前端
     *
     * @param file
     * @throws Exception
     */
    @RequestMapping(value = "/importDataNormal", method = RequestMethod.POST)
    public String importDataNormal(@RequestParam(name = "file") MultipartFile file, HttpServletResponse response) {
        List<User> userList = null;
        FileInputStream input = null;
        try {
            //校验用户上传到额文件
            checkFile(file);
            userList = new ExcelImportUtil<User>(User.class).readExcel(file.getInputStream(), 2, 0);
            //对数据进行校验
            Map<String, Object> checkResultMap = userService.checkData(userList);
            Boolean flag = (Boolean) checkResultMap.get("flag");
            if (!flag) {
                //说明上传的数据中存在问题,不能导入
                //首先利用nio将  excel-template/user-import-error-template.xlsx 复制到  user-import-error-template.xlsx
                copyFile();
                File targetFile = new File("user-import-error-template.xlsx");
                List<User> records = (List<User>) checkResultMap.get("records");
                InputStream is = new FileInputStream(targetFile);
                 String fileName = "用户信息上传失败详情表";
                new ExcelWithTemplateExportUtil<User>(User.class, 2, 1).exportToLocalFile(is, records, targetFile,true);

                //将写入后的excel文件上传至fastdfs
                input = new FileInputStream(targetFile);
                MultipartFile multipartFile = new MockMultipartFile("file", file.getName(), "text/plain", IOUtils.toByteArray(input));
                FastDFSFile fastDFSFile = new FastDFSFile(fileName, multipartFile.getBytes(), "xlsx");
                String[] uploadResult = FastDFSClient.upload(fastDFSFile);
                //封装返回结果
                String url = FastDFSClient.getTrackerUrl() + uploadResult[0] + "/" + uploadResult[1];
                //删除本地的excel临时文件
                boolean delete = targetFile.delete();
                if (delete) {
                    log.info("删除本地临时文件成功");
                }
                //最后拼接url是为了在浏览器中下载时的文件名不是一串英文而是自己在这里自定义的文件名称
                return "操作失败,具体信息请查看文件:" + url + "?filename=" + fileName + ".xlsx";
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (input != null) {
                try {
                    input.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        userService.insertList(userList);
        return "操作成功!";
    }

    private void checkFile(MultipartFile file) {
        log.info("{}类{}方法中,开始校验用户上传的excel文件是否合法", "UserController", "checkFile");
        XSSFWorkbook workbook = null;
        InputStream inputStream = null;
        try {
            //对文件做健壮性判断
            if (file == null || StringUtils.isBlank(file.getOriginalFilename())) {
                throw new RuntimeException("文件格式有误!");
            }
            String originalFilename = file.getOriginalFilename();
            String[] splitName = originalFilename.split("\\.");
            String extendName = splitName[splitName.length - 1];
            if (StringUtils.isBlank(extendName) || !"xlsx".equalsIgnoreCase(extendName)) {
                throw new RuntimeException("文件格式有误!");
            }
            //比较用户上传表格中的字段行是否和模板的字段行一致
            inputStream = file.getInputStream();
            workbook = new XSSFWorkbook(inputStream);
            XSSFSheet sheet = workbook.getSheetAt(0);
            XSSFRow row = sheet.getRow(1);
            String username = row.getCell(1).getStringCellValue();
            String age = row.getCell(2).getStringCellValue();
            String address = row.getCell(3).getStringCellValue();
            String school = row.getCell(4).getStringCellValue();
            String national = row.getCell(5).getStringCellValue();
            if (!"用户名".equals(username) || !"年龄".equals(age) || !"地址".equals(address) || !"学校".equals(school) || !"国家".equals(national)) {
                throw new RuntimeException("文件格式有误!");
            }
            log.info("校验文件完成!");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (workbook != null) {
                    workbook.close();
                }
                if (inputStream != null) {
                    inputStream.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 利用nio将  excel-template/user-import-error-template.xlsx 复制到  user-import-error-template.xlsx
     */
    private void copyFile() {
        log.info("{}类中{}方法中,利用nio将  excel-template/user-import-error-template.xlsx 复制到  user-import-error-template.xlsx", "UserController", "copyFile");
        FileInputStream fileInputStream = null;
        FileOutputStream fileOutputStream = null;
        try {
            Resource classPathResource = new ClassPathResource("excel-template/user-import-error-template.xlsx");
            fileInputStream = new FileInputStream(classPathResource.getFile());

            fileOutputStream = new FileOutputStream("user-import-error-template.xlsx");

            FileChannel fileInputStreamChannel = fileInputStream.getChannel();
            FileChannel fileOutputStreamChannel = fileOutputStream.getChannel();

            fileInputStreamChannel.transferTo(0, fileInputStreamChannel.size(), fileOutputStreamChannel);
            log.info("复制完成!");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭流
            try {
                if (fileInputStream != null) {
                    fileInputStream.close();
                }
                if (fileOutputStream != null) {
                    fileOutputStream.close();
                }

            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }


    /**
     * //下载模板文件
     * downloadTemplate(){
     * window.location.href="../../template/ordersetting_template.xlsx";
     * }
     *
     * @param response
     * @throws Exception
     */
    @RequestMapping(value = "/downloadTemplate", method = RequestMethod.GET)
    public void downloadTemplate(HttpServletResponse response) {
        InputStream is = null;
        XSSFWorkbook workbook = null;
        try {
            Resource resource = new ClassPathResource("excel-template/user-template.xlsx");
            is = new FileInputStream(resource.getFile());
            workbook = new XSSFWorkbook(is);
            String fileName = "用户信息记录表模板.xlsx";
            response = new ExcelWithTemplateExportUtil<>().setResponseHeaders(response, fileName);
            workbook.write(response.getOutputStream());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (is != null) {
                    is.close();
                }
                if (workbook != null) {
                    workbook.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }


    }

    /**
     * 基于模板导出数据
     *
     * @param response response
     * @throws Exception
     */
    @RequestMapping(value = "/exportExcel", method = RequestMethod.GET)
    public void exportExcel(HttpServletResponse response) throws Exception {
        String fileName = "用户信息记录表.xlsx";
        Resource resource = new ClassPathResource("excel-template/user-template.xlsx");
        InputStream is = new FileInputStream(resource.getFile());
        List<User> userList = userService.findAll();
        new ExcelWithTemplateExportUtil<User>(User.class, 2, 0).export(response, is, userList, fileName,true);
        is.close();
    }


    /**
     * 不基于模板导出数据  使用的是SXSSF
     *
     * @param response
     * @throws Exception
     */
    @RequestMapping(value = "/exportWithoutExcel", method = RequestMethod.GET)
    public void exportWithoutExcel(HttpServletResponse response) throws Exception {
        String fileName = "用户信息记录表1.xlsx";
        //标题
        String[] titles =
                "编号,用户名,年龄,地址,学校,国家".split(",");
        List<User> userList = userService.findAll();
        new ExcelExportWithoutTemplateUtil<User>(User.class, 2).export(response, userList, titles, fileName);
    }
}
